package core.matrix;

import core.iterfaces.Matrix;
import core.iterfaces.Vec;
import core.vec.DenseVec;
import core.vec.SparseVec;
import exception.NotSupportException;

/**
 * 对称矩阵的存储按照对角线进行存储
 * a[j+k,j]=A.diag[j+nk-k(k-1)/2] k>=0
 * a[i,j]=a[j,i] i<j
 *    1 2 3
 * A=[4 5 6]
 *    7 8 9
 */
public class SymmetricMatrix implements Matrix {
    /**
     * 矩阵的长和宽，因为对称矩阵是方阵，因此只记录一个
     */
    private Integer n;
    /**
     * 存放对角线的数组
     */
    private Double[] diag;

    public SymmetricMatrix(Integer n){
        this.n = n;
        diag = new Double[n * (n + 1) / 2];
        for (int i = 0; i < diag.length; i++) {
            diag[i]=0.0;
        }
    }


    @Override
    public Matrix zero() {
        return new SymmetricMatrix(this.n);
    }

    @Override
    public Matrix zero(int rowLen, int colLen) {
        if(rowLen!=colLen){
            throw new RuntimeException("对称矩阵行列必须相等");
        }
        return new SymmetricMatrix(rowLen);
    }

    @Override
    public double get(int i, int j) {
        if(i<0||i>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(i>=j){
            int k = i-j;
            return diag[k*n-k*(k-1)/2+j];
        }
        return get(j,i);
    }

    @Override
    public void set(int i, int j, double value) {
        if(i<0||i>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(i>=j){
            int k = i-j;
            diag[k*n-k*(k-1)/2+j]=value;
        }
        else{
            set(j,i,value);
        }
    }

    @Override
    public Vec getRow(int i) throws NotSupportException {
        Vec result = new DenseVec(n);
        if(i<0||i>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        for (int j = 0; j < n; j++) {
            result.set(j,get(i,j));
        }
        return result;
    }

    @Override
    public Vec getCol(int j) {
        Vec result = new DenseVec(n);
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        for (int i = 0; i < n; i++) {
            result.set(i,get(i,j));
        }
        return result;
    }

    @Override
    public Vec getSubRow(int i, int begin, int end) throws NotSupportException {
        if(i<0||i>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(begin<0||begin>n-1){
            throw new IndexOutOfBoundsException("传入的参数begin:"+begin+" 不符合矩阵列数范围");
        }
        if(end<0||end>n){
            throw new IndexOutOfBoundsException("传入的参数end:"+end+" 不符合矩阵列数范围");
        }
        Vec result = new DenseVec(end-begin);
        if(i<n&&begin<=i&&i<end){
            result.set(i-begin,get(i,i));
        }

        return result;
    }

    @Override
    public Vec getSubCol(int j, int begin, int end) throws NotSupportException {
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(begin<0||begin>n-1){
            throw new IndexOutOfBoundsException("传入的参数begin:"+begin+" 不符合矩阵行数范围");
        }
        if(end<0||begin>n){
            throw new IndexOutOfBoundsException("传入的参数end:"+end+" 不符合矩阵行数范围");
        }
            Vec result = new DenseVec(end-begin);
        if(j<n&&begin<=j&&j<end){
            result.set(j-begin,get(j,j));
        }
        return result;
    }

    @Override
    public int getRowLen() {
        return n;
    }

    @Override
    public int getColLen() {
        return n;
    }

    @Override
    public boolean isDense() {
        return true;
    }

    @Override
    public boolean isPositiveDefinite() {
        return false;
    }

    @Override
    public double norm2() {
        return 0;
    }

    @Override
    public Matrix toSparse() throws NotSupportException {
        Matrix result = new SparseMatrix(n,n);
        for (int i=0;i<Math.min(n,n);i++){
            result.set(i,i,get(i,i));
        }
        return result;
    }

    @Override
    public Matrix toDense() throws NotSupportException {
        Matrix result = new DenseMatrix(n,n);
        for (int i=0;i<Math.min(n,n);i++){
            result.set(i,i,get(i,i));
        }
        return result;
    }

    @Override
    public Vec getKDiag(int k) throws NotSupportException {
        int realK = k;
        if(k<0){
            realK = -k;
        }
        int index = 0;
        for (int i = 0; i < realK; i++) {
            index+=(n-i);
        }
        Vec result = new DenseVec(n-realK);
        for (int i = 0; i < (n-realK); i++) {
            result.set(i,diag[index+i]);
        }
        return result;
    }


    @Override
    public Matrix muti(double a, boolean isCovered) {
        if(isCovered){
            for (int i = 0; i < diag.length; i++) {
                diag[i] = diag[i]*a;
            }
            return this;
        }
        else{
            SymmetricMatrix result = new SymmetricMatrix(n);
            for (int i = 0; i < result.diag.length; i++) {
                result.diag[i] = result.diag[i]*a;
            }
            return  result;
        }
    }

    @Override
    public Vec muti(Vec v) throws NotSupportException {
        if(n!=v.len()){
            throw new NotSupportException("矩阵列和向量行数目不等");
        }
        Vec result = new DenseVec(n);
        for (int i=0;i<n;i++){
            result.set(i,diag[i]*v.get(i));
        }
        for (int k = 1; k < n; k++) {
            int t = n*k-k*(k-1)/2;
            /**
             * y=D(A,k)x
             */
            for (int i = 0; i < n-k; i++) {
                result.set(i,diag[i+t]*v.get(i+k)+result.get(i));
            }
            /**
             * y=D(A,k)Tx
             */
            for (int i = 0; i < n-k; i++) {
                result.set(i+k,diag[i+t]*v.get(i)+result.get(i+k));
            }
        }
        return result;
    }

    @Override
    public Matrix muti(Matrix other) throws NotSupportException {
        return Matrix.super.muti(other);
    }

    @Override
    public boolean isSquare() {
        return true;
    }



    @Override
    public boolean isSymmetric() {
        return true;
    }


    @Override
    public void exchangeRow(int i, int j) {
        throw new RuntimeException("不支持此操作");
    }

    @Override
    public void exchangeCol(int i, int j) {
        throw new RuntimeException("不支持此操作");
    }

    @Override
    public double fnorm() {
        double result = 0.0;
        for(int i=0;i<diag.length;i++){
            result+= Math.pow(diag[i],2);
            if(i>=n){
                result+= Math.pow(diag[i],2);
            }
        }
        return result;
    }
}
